/*
 *      Copyright 2012-2013 Battams, Derek
 *       
 *       Licensed under the Apache License, Version 2.0 (the "License");
 *       you may not use this file except in compliance with the License.
 *       You may obtain a copy of the License at
 *
 *          http://www.apache.org/licenses/LICENSE-2.0
 *
 *       Unless required by applicable law or agreed to in writing, software
 *       distributed under the License is distributed on an "AS IS" BASIS,
 *       WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *       See the License for the specific language governing permissions and
 *       limitations under the License.
 */
package org.schedulesdirect.api;

import java.io.IOException;
import java.util.Arrays;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.json.JSONException;
import org.json.JSONObject;
import org.schedulesdirect.api.exception.InvalidJsonObjectException;
import org.schedulesdirect.api.exception.InvalidResponseException;

/**
 * A Headend represents a specific location for which listings data is available
 * 
 * <p>Only an EpgClient can instantiate objects of this class.</p>
 * 
 * <p>When there's a discrepancy between the descriptions of data found in this source code and
 * that found <a href="https://github.com/rkulagowski/tv_grab_na_sd/wiki">here</a> then the 
 * latter web source will always take precedence!</p>
 * 
 * @author Derek Battams &lt;derek@battams.ca&gt;
 *
 */
public class Headend {
	static private final Log LOG = LogFactory.getLog(Headend.class);
	
	/**
	 * The JSON field containing the headend id data
	 */
	static public final String JSON_ID = "headend";
	
	/**
	 * The JSON field containing the headend name data
	 */
	static public final String JSON_NAME = "name";
	
	/**
	 * The JSON field containing the headend location data
	 */
	static public final String JSON_LOCATION = "location";
		
	private String id;
	private String name;
	private String location;
	private Lineup[] lineups;
	private EpgClient epgClnt;
	
	/**
	 * Constructor; used to build a specific Headend instance by unique id
	 * @param id The unique id of the instance to be created
	 * @param clnt The EpgClient this instance is to be attached to
	 */
	Headend(String id, EpgClient clnt) {
		this.id = id;
		this.epgClnt = clnt;
		lineups = null;
	}
	
	/**
	 * Constructor; used to build an instance from a source JSON object
	 * @param src The JSON object from which to build this instance
	 * @param clnt The EpgClient this instance is to be attached to
	 * @throws InvalidJsonObjectException Thrown if src is not in the expected format
	 */
	Headend(JSONObject src, EpgClient clnt) throws InvalidJsonObjectException {
		LOG.trace(String.format("INPUT: %s", src.toString()));
		epgClnt = clnt;
		try {
			id = src.getString(JSON_ID);
			name = src.getString(JSON_NAME);
			location = src.getString(JSON_LOCATION);
			if(id.startsWith("PC:"))
				location = String.format("%s (%s)", location, id.substring(3));
		} catch(JSONException e) {
			throw new InvalidJsonObjectException(e);
		}
		lineups = null;
	}	

	/**
	 * @return The headend's unique id
	 */
	public String getId() {
		return id;
	}

	/**
	 * @return The headend's name; may be empty string if not available
	 */
	public String getName() {
		return name;
	}

	/**
	 * @return The headend's location; may be empty string if not available
	 */
	public String getLocation() {
		return location;
	}

	/**
	 * Get an array of all available lineups for this headend
	 * 
	 * <p><b>NOTE:</b> The contents of this array is never filled in until first accessed (i.e. lazy initialization)</p>
	 * 
	 * @return The array of available lineups; never null, but could be an empty array if no lineups were found for this headend
	 * @throws IOException Thrown on any IO error accessing the raw data
	 * @throws InvalidResponseException Thrown if any response from the data feed was not in the expected format
	 */
	public Lineup[] getLineups() throws IOException, InvalidResponseException {
		if(lineups == null) {
			lineups = epgClnt.fetchLineups(this);
			if((name == null || location == null) && lineups.length > 0) {
				name = lineups[0].getName();
				location = lineups[0].getLocation();
			}
		}
		return lineups;
	}
	
	/* (non-Javadoc)
	 * @see java.lang.Object#toString()
	 */
	@Override
	public String toString() {
		final int maxLen = 5;
		StringBuilder builder = new StringBuilder();
		builder.append("Headend [id=");
		builder.append(id);
		builder.append(", name=");
		builder.append(name);
		builder.append(", location=");
		builder.append(location);
		builder.append(", lineups=");
		builder.append(lineups != null ? Arrays.asList(lineups).subList(0,
				Math.min(lineups.length, maxLen)) : null);
		builder.append(", epgClnt=");
		builder.append(epgClnt);
		builder.append("]");
		return builder.toString();
	}
}
